package com.hhd.flow.engine.cmd.impl.virtual;

import com.alibaba.fastjson.JSONObject;
import com.hhd.flow.engine.FlowEngine;
import com.hhd.flow.engine.cmd.FlowCommandExecutor;
import com.hhd.flow.engine.utils.CommonUtils;
import com.hhd.flow.engine.vo.ApproveType;
import com.hhd.flow.engine.vo.FlowModel;
import com.hhd.flow.engine.vo.FlowUser;
import com.hhd.flow.engine.vo.UserManualSelect;
import com.hhd.flow.entity.*;
import com.hhd.flow.exception.FlowException;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.SuperBuilder;

import java.util.List;
import java.util.stream.Collectors;

@Getter
@Setter
@SuperBuilder
public class VirtualCompleteUserTaskCommand extends VirtualPassAbleCommand<UserManualSelect> {
    private String flowUserTaskId;//待审批的用户任务
    JSONObject formModel;       //表单数据

    //下面是运转过程中的数据
    UserManualSelect userManualSelect = new UserManualSelect();
    FlowEngine engine;
    FlowCommandExecutor commandExecutor;

    private FlowUserTask flowUserTask;
    private FlowProcessInstance processInstance;
    private FlowModel flowModel;
    private VirtualContext context;

    @Override
    public UserManualSelect execute() {
        userManualSelect = new UserManualSelect();

        prepare();

        createContext();

        prepareContext();

        completeFlowUserTask();

        passTask(context);

        return userManualSelect;
    }

    private void completeFlowUserTask() {
        context.getHistoryUsers().add(new FlowUser(this.flowUserTask.getUserId(), this.flowUserTask.getUsername()));
        for (FlowTask activeTask : context.getActiveTasks()) {
            if (activeTask.getId().equals(this.flowUserTask.getTaskInstanceId())) {
                activeTask.setExecuteCount(activeTask.getExecuteCount() + 1);
                break;
            }
        }
        context.setActiveUserTasks(context.getActiveUserTasks()
                .stream().filter(f -> f.getId().equals(this.flowUserTask.getId()))
                .collect(Collectors.toList()));
    }

    private void prepareContext() {
        loadHistoryUsers();

        loadActiveUserTasks();

        loadActiveTasks();

        loadGatewayExecutions();
    }

    private void loadGatewayExecutions() {
        List<FlowGatewayExecution> list = getEngine().getFlowGatewayExecutionService().lambdaQuery()
                .eq(FlowGatewayExecution::getProcessInstanceId, processInstance.getId())
                .list();
        context.getGatewayExecutions().addAll(list);
    }

    private void loadActiveTasks() {
        List<FlowTask> list = getEngine().getFlowTaskService().lambdaQuery()
                .eq(FlowTask::getProcessInstanceId, processInstance.getId())
                .list();
        context.getActiveTasks().addAll(list);
    }

    private void loadActiveUserTasks() {
        List<FlowUserTask> list = getEngine().getFlowUserTaskService().lambdaQuery()
                .eq(FlowUserTask::getProcessInstanceId, processInstance.getId())
                .eq(FlowUserTask::getNotify, false)
                .list();
        context.getActiveUserTasks().addAll(list);
    }

    private void loadHistoryUsers() {
        List<FlowUser> historyUsers = getEngine().getFlowUserTaskHistoryService().lambdaQuery()
                .eq(FlowUserTaskHistory::getProcessInstanceId, processInstance.getId())
                .eq(FlowUserTaskHistory::getApproveType, ApproveType.approve)
                .list().stream().map(this::toFlowUser)
                .collect(Collectors.toList());
        historyUsers.add(new FlowUser(processInstance.getApplyBy(), processInstance.getApplyByName()));

        historyUsers.add(new FlowUser(flowUserTask.getUserId(), flowUserTask.getUsername()));
        context.setHistoryUsers(historyUsers);
    }

    private FlowUser toFlowUser(FlowUserTaskHistory flowUserTaskHistory) {
        return FlowUser.builder()
                .id(flowUserTaskHistory.getUserId())
                .username(flowUserTaskHistory.getUsername()).build();
    }

    private void prepare() {
        loadFlowUserTask();

        loadFlowProcessInstance();

        loadFlowModel();
    }

    private void loadFlowModel() {
        flowModel = loadFlowModelByProcessInstanceId(processInstance.getId());
    }

    private void createContext() {
        context = new VirtualContext();
        context.setFormModel(formModel);
        context.setFormTypeId(processInstance.getFormTypeId());
        context.setFormId(processInstance.getFormId());
        context.setApplyBy(new FlowUser(processInstance.getApplyBy(), processInstance.getApplyByName()));
        context.setProcessDefinitionId(processInstance.getProcessDefinitionId());
        context.setProcessInstance(processInstance);
        context.setFlowModel(flowModel);
        context.setUserManualSelect(userManualSelect);
    }

    private void loadFlowProcessInstance() {
        processInstance = getEngine().getFlowProcessInstanceService().getById(flowUserTask.getProcessInstanceId());
        CommonUtils.isEmptyThrow(flowUserTask, new FlowException("没有找到流程实例: " + flowUserTask.getProcessInstanceId() + "请刷新页面后重试"));
    }

    private void loadFlowUserTask() {
        flowUserTask = getEngine().getFlowUserTaskService().getById(flowUserTaskId);
        CommonUtils.isEmptyThrow(flowUserTask, new FlowException("没有找到用户任务: " + flowUserTaskId + "请刷新页面后重试"));
    }
}
